package top.wilsonlv.jaguar.cloud.auth.extension.device;

import org.springframework.security.authentication.AccountStatusException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.util.StringUtils;
import top.wilsonlv.jaguar.cloud.auth.sdk.token.DeviceAuthenticationToken;
import top.wilsonlv.jaguar.commons.web.util.WebUtil;
import top.wilsonlv.jaguar.oauth2.security.Oauth2SecurityConstant;

import javax.servlet.http.HttpServletRequest;

import static top.wilsonlv.jaguar.cloud.auth.extension.OAuth2ExtensionContant.*;

/**
 * @author lvws
 * @since 2022/3/30 0030
 */
public class DeviceTokenGranter extends AbstractTokenGranter {

    private static final String GRANT_TYPE = "device";

    private final AuthenticationManager authenticationManager;

    public DeviceTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices,
                              ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) {
        super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
        this.authenticationManager = authenticationManager;
    }

    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
        HttpServletRequest request = WebUtil.getRequest();
        assert request != null;

        String userIdStr = request.getParameter(QUERY_PARAMETER_USER_ID_KEY);
        if (!StringUtils.hasText(userIdStr)) {
            throw new InvalidGrantException("用户ID为非空");
        }
        long userId = Long.parseLong(userIdStr);

        String deviceAuthType = request.getParameter(QUERY_PARAMETER_DEVICE_AUTH_TYPE_KEY);
        if (!StringUtils.hasText(deviceAuthType)) {
            throw new InvalidGrantException("设备授权方式为非空");
        }

        String deviceUid = request.getParameter(QUERY_PARAMETER_DEVICE_UID_KEY);
        if (!StringUtils.hasText(deviceUid)) {
            throw new InvalidGrantException("设备UID为非空");
        }

        String timestampStr = request.getParameter(Oauth2SecurityConstant.PARAMETER_TIMESTAMP);
        long timestamp;
        if (!StringUtils.hasText(timestampStr)) {
            throw new InvalidGrantException("时间戳为非空");
        } else {
            timestamp = Long.parseLong(timestampStr);
        }

        String nonce = request.getParameter(Oauth2SecurityConstant.PARAMETER_NONCE);
        if (!StringUtils.hasText(nonce)) {
            throw new InvalidGrantException("随机数为非空");
        }

        String sign = request.getParameter(Oauth2SecurityConstant.PARAMETER_SIGN);
        if (!StringUtils.hasText(sign)) {
            throw new InvalidGrantException("签名为非空");
        }

        DeviceAuthenticationToken token = new DeviceAuthenticationToken(userId,
                deviceUid, deviceAuthType, timestamp, nonce, sign, request.getParameterMap());

        Authentication authentication;
        try {
            authentication = authenticationManager.authenticate(token);
        } catch (AccountStatusException ase) {
            throw new InvalidGrantException(ase.getMessage());
        }

        OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
        return new OAuth2Authentication(storedOAuth2Request, authentication);
    }
}
